using System;
using System.Collections.Generic;
using Google.Protobuf;
using UnityEngine;

namespace Shioho.Net
{
    public abstract class AProtoSendMsgController<ReqPaser, ResPaser, Res> : IProtoSendMsgController
        where ReqPaser : IProtoMsgPaser
        where ResPaser : IProtoResponseMsgPaser
        where Res : IMessage
    {
        int IProtoMsgController.ProtoId => _protoId;

        private IProtoMsgPaser _reqPaser;
        private IProtoResponseMsgPaser _resPaser;
        private int _protoId;
        private Dictionary<int, object> _contextDic = new Dictionary<int, object>();

        protected abstract void OnProcessSuccess(Res data, object context);
        protected abstract void OnProcessFailed(Res data, object context);

        public AProtoSendMsgController()
        {
            _reqPaser = Activator.CreateInstance(typeof(ReqPaser)) as IProtoMsgPaser;
            _resPaser = Activator.CreateInstance(typeof(ResPaser)) as IProtoResponseMsgPaser;
            _protoId = _resPaser.ProtoId;
        }

        public void Process(int seqId, byte[] buffer)
        {
            try
            {
                var data = (Res)_resPaser.Decode(buffer);
                _contextDic.TryGetValue(seqId, out var context);
                _contextDic.Remove(seqId);

                if (_resPaser.GetCode(data) == (int)ProtoMsgCodeDefine.Success)
                {
                    OnProcessSuccess(data, context);
                }
                else
                {
                    Debug.LogError($"On Response ProcessFailed: {data}");
                    OnProcessFailed(data, context);
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public byte[] GetBuffer(int seqId, IMessage data)
        {
            var protoBuf = _reqPaser.Encode(data);
            return ProtoUtil.GetReqBuffer(seqId, _protoId, protoBuf);
        }

        public void AddContext(int seqId, object context)
        {
            _contextDic[seqId] = context;
        }
    }

    public abstract class ATpro2PushMsgController<PushPaser, Push> : IProtoPushMsgController
        where PushPaser : IProtoMsgPaser
        where Push : IMessage
    {
        public int ProtoId => _protoId;

        private int _protoId;
        private IProtoMsgPaser _pushPaser;

        protected abstract void OnProcessSuccess(Push data);

        public ATpro2PushMsgController()
        {
            _pushPaser = Activator.CreateInstance(typeof(PushPaser)) as IProtoMsgPaser;
            _protoId = _pushPaser.ProtoId;
        }

        void IProtoPushMsgController.Process(byte[] buffer)
        {
            try
            {
                var data = (Push)_pushPaser.Decode(buffer);
                OnProcessSuccess(data);
            }
            catch (Exception e)
            {
                throw e;
            }
        }
    }

}
